refactor(utils): canonical subscriber-set observable plus exact-dupe cleanups - #3047
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new shared utilities intended to reduce duplicated patterns across the codebase, specifically a canonical subscribe/notify listener registry and a shared filesystem probe helper.
Changes:
- Introduces
createSubscriberSet()insrc/utils/subscriber-set.tsto standardize Set-backed subscribe/notify behavior (snapshot during notify, optional listener-error hook). - Introduces
findFirstExistingFile()insrc/modules/server/fs-probe.tsto consolidate repeated “probe a list of paths viastat” logic.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/utils/subscriber-set.ts | Adds a generic subscriber-set helper intended to replace duplicated Set-based observables. |
| src/modules/server/fs-probe.ts | Adds a helper to probe multiple candidate paths and return the first existing file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eada5dd87d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…cleanups Six modules hand-rolled the same Set-based subscribe/notify observable with inconsistent notify semantics (live vs snapshot iteration, varying error isolation). This adds createSubscriberSet to #veryfront/utils and migrates the accidental copies, plus two byte-identical dupe groups found by the duplicate scanner: - createSubscriberSet<Args>(onListenerError?): snapshot-during-notify (safe mid-notify unsubscribe) with isolated listener errors; migrated observability/error-collector, observability/log-buffer, server/reload-notifier (both listener sets, log messages preserved), and workflow/claude-code/websocket-publisher - Server-Timing helpers (roundMs, formatDuration, sanitizeMetricName) deduplicated: proxy/server-timing now imports them from observability/request-profiler - modules/server: four identical findFirstSecureFile/findFirstPlatformFile copies collapsed into one structurally-typed findFirstExistingFile Deliberately left: rendering/client navigation-store + react/runtime mirror (documented cross-bundle contract), workflow event-publisher (throwing handlers intentionally propagate), proxy Redis channel map (keyed lifecycle, different shape).
eada5dd to
121b590
Compare
|
Review comments addressed in the force-pushed commit:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/utils/subscriber-set.ts:23
createSubscriberSetis a new canonical primitive that changes notification semantics across multiple modules (snapshot iteration, error isolation). It should have focused unit tests covering: (1) snapshot behavior when listeners unsubscribe/subscribe during notify, (2) listener exceptions not stopping later listeners, and (3) a throwingonListenerErrornot breaking notification.
export function createSubscriberSet<Args extends unknown[] = []>(
onListenerError?: (error: unknown) => void,
): SubscriberSet<Args> {
const listeners = new Set<(...args: Args) => void>();
…r test off deleted accessor
…ASCII punctuation
Summary
Third PR in the code-reduction campaign (after #3045, #3046). Six modules hand-rolled the same Set-based subscribe/notify observable with inconsistent notify semantics; this adds one canonical
createSubscriberSetto#veryfront/utilsand migrates the accidental copies, plus two byte-identical dupe groups flagged bydeno task dupes, plus fixes for two review findings against the already-merged #3045.Net: −1 line (+163/−164, 13 files). The raw counter is thin because ~40 lines are review-driven additions fixing #3045 fallout (see below); the consolidation itself removes ~120 lines of duplicated logic. 2634 unit tests pass.
Changes
createSubscriberSet<Args>(onListenerError?)— subscribe→unsubscribe, snapshot-during-notify, isolated listener errors (including a throwingonListenerErroritself),size/clear. Migrated:observability/error-collector,observability/log-buffer,server/reload-notifier(both listener sets, per-set error logs preserved; deadgetInvalidateListenerCountremoved),workflow/claude-code/websocket-publisher.Two of these sites previously iterated the live Set during notify — a listener unsubscribing mid-notify could skip listeners. Snapshot semantics closes that bug class.
roundMs/formatDuration/sanitizeMetricNamewere duplicated betweenproxy/server-timing.tsandobservability/request-profiler.ts; proxy now uses the exportedbuildServerTimingValue/roundMsand the format helpers went back to private.modules/server— four identicalfindFirstSecureFile/findFirstPlatformFilecopies collapsed into one structurally-typedfindFirstExistingFile(fs-probe.ts).plugin-loader:encodeBase64(code)fordata:URLs emits Latin-1 bytes for chars in[0x80–0xFF]via btoa, corrupting non-ASCII plugin source outside Deno. NowencodeBase64Bytes(new TextEncoder().encode(code)), restoring the pre-refactor(utils): consolidate hash, sleep, and base64 helpers onto canonical utils #3045 always-UTF-8 behavior.btoainbase64urlEncodeBytes: now routed through the new fallback-safeencodeBase64Bytes(btoa → Buffer → clear error), andencodeBase64's non-Latin1 fallback reuses it.Deliberately left (documented in code or genuinely different)
rendering/client/navigation-store+react/runtime/coremirror — documented cross-bundle contract; react runtime bundle intentionally imports nothingworkflow/claude-code/event-publisher— throwing handlers intentionally propagate; converting would change behaviorVerification
deno task verify:quickexit 0;deno task test:unit2634 passed / 0 failed; affected suites (observability, proxy, modules/server, workflow, utils, html) pass unmodified; pre-push hook (fmt + full suite) passed on the amended commit